
function Scene3D(canvasId){
	this.canvasId = canvasId;
	this.canvas = null;
	this.context = null;
	this.animationContext = null;
	this.cameraPosition = null;		
	this.cameraAngles = null;
	// shapes
	this.shapes = null;
	// matrices
	this.mvMatrix = null;
	this.pMatrix = null;
	// shaders
	this.shaderManager = null;
	this.shaderProgram = null;
		
	this.initScene = function(){
		// init canvas
		this.canvas = document.getElementById(canvasId);
		this.context =  this.canvas.getContext("webgl") || this.canvas.getContext("experimental-webgl");
		// init context
		this.context.viewportWidth = this.canvas.width;
		this.context.viewportHeight = this.canvas.height;
		
		this.animationContext = new Animation3DContext(this);
		this.cameraPosition = {x:0,y:0,z:0};
		this.cameraAngles = {x:0,y:0,z:0};
		
		// shapes
		this.shapes = new Array();
		
		// matrices
		this.mvMatrix = mat4.create();
		this.pMatrix = mat4.create();
		
		// shaders
		this.shaderManager = new ShaderManager(this.context);
		this.shaderProgram = null;
		
		// camera animations
		this.cameraAnimations = new Array();
	};
	this.initScene();
	
	this.reset = function(){
		var self = this;
		this.animationContext.stop(function(){
			self.animationContext.animations = null;
			self.animationContext = null;
			
			self.animationContext = new Animation3DContext(self);
			self.cameraAnimations = new Array();

			self.cameraPosition = {x:0,y:0,z:0};
			self.cameraAngles = {x:0,y:0,z:0};			
			
			// reset shape positions...
			for(var i=0;i<self.shapes.length;i++){
				self.shapes[0].reset();
			}
						
			self.draw();			
		});		
	}
		
	this.moveCamera = function(value){
		this.cameraPosition = value;
		this.draw();
	}
	this.rotateCamera = function(value){
		this.cameraAngles = value;
		this.draw();
	}	
	this.addCameraAnimation = function(animation){	
		animation.scene = this;
		this.cameraAnimations.push(animation);
		this.animationContext.add(animation);		
	}	
	
	this.addShape= function(shape){
		this.shapes.push(shape);
		shape.scene = this;
		shape.added();
	}
	
	
	
	this.initShaders = function(shaderNames){
		if(!shaderNames)return;
		this.shaderProgram = this.context.createProgram();
		for(var i =0;i<shaderNames.length;i++){
			// select shader from repo
			this.shaderManager.selectShader(shaderNames[i]);
			
			var shader = this.shaderManager.getShader(shaderNames[i]);
			if(shader)
				this.context.attachShader(this.shaderProgram, shader);
		}
		this.context.linkProgram(this.shaderProgram);
		if (!this.context.getProgramParameter(this.shaderProgram, this.context.LINK_STATUS)) {
			alert("Could not initialise shaders");
			return;
		}
		this.context.useProgram(this.shaderProgram);
		
		// add vertex attribute - might need to change to make it configurable
		this.shaderProgram.vertexPositionAttribute = this.context.getAttribLocation(this.shaderProgram, "aVertexPosition");
		this.context.enableVertexAttribArray(this.shaderProgram.vertexPositionAttribute);
		
		// add color attribute - might need to change to make it configurable
		this.shaderProgram.vertexColorAttribute = this.context.getAttribLocation(this.shaderProgram, "aVertexColor");
		this.context.enableVertexAttribArray(this.shaderProgram.vertexColorAttribute);
		
		// set matrices ... i do not understand what these are yet
		this.shaderProgram.pMatrixUniform = this.context.getUniformLocation(this.shaderProgram, "uPMatrix");
		this.shaderProgram.mvMatrixUniform = this.context.getUniformLocation(this.shaderProgram, "uMVMatrix");
	}
	
	
	this.setMatrixUniforms = function () {
		this.context.uniformMatrix4fv(this.shaderProgram.pMatrixUniform, false, this.pMatrix);
		this.context.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.mvMatrix);
	}
	this.draw = function(){	
		
		for(var i=0;i<this.shapes.length;i++){
			var shape = this.shapes[i];
			//shape.initBuffers();
		}
		//debugger;
		this.context.viewport(0, 0, this.context.viewportWidth, this.context.viewportHeight);
		this.context.clear(this.context.COLOR_BUFFER_BIT | this.context.DEPTH_BUFFER_BIT);					
		
		// need to check what these are
		mat4.perspective(45, this.context.viewportWidth / this.context.viewportHeight, 0.1, 100.0, this.pMatrix);
		
		
		
		// rotates something - i guess the perspective? need to learn exactly what this is
		//mat4.rotate(this.mvMatrix, this.degToRad(this.rTri), [0, 1, 0]);
		
		// draw shapes
		for(var i=0;i<this.shapes.length;i++){
			this.mvPushMatrix();
			var shape = this.shapes[i];
			shape.draw();
			this.mvPopMatrix();
		}
	}
	
	
	
	
	this.mvMatrixStack = [];
	 this.mvPushMatrix = function() {
		var copy = mat4.create();
		mat4.set(this.mvMatrix, copy);
		this.mvMatrixStack.push(copy);
	  }

		this.mvPopMatrix = function() {
		if (this.mvMatrixStack.length == 0) {
		  throw "Invalid popMatrix!";
		}
		this.mvMatrix = this.mvMatrixStack.pop();
	  }
	  this.degToRad = function (degrees) {
		return degrees * Math.PI / 180;
	}
}
